home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-04 | 19.0 KB | 651 lines | [TEXT/MPS ] |
- //234567890123456789012345678901234567890123456789012345678901234567890123456789
- //===========================================================================
- // File: SampleServerModule.c
- //
- // This is the sample server-side add-on security module for Apple
- // Remote Access. It works with its corresponding client-side module to
- // prompt the user for an extra password and authenticate the user if the
- // user enters the correct password. The system administrator can setup the
- // password using the sample server configuration module.
- //
- // When invoked this code resource will send a password request to the client
- // code, which will then display a password dialog box. The client then
- // sends the user password back to this module. If the password is correct
- // the user is authenticated.
- //
- // The module implements a state machine. The states of the state machine
- // are defined in the TServerCodeStates. The current state is passed to
- // the completion proc as the CompletionParam, and to the TickleRoutine as
- // the LongParam.
- //
- // Copyright © 1992,1993 Apple Computer Inc.
- // All rights reserved
- //
- // Author: Farzad Sarabi
- //
- // Modification history:
- //
- // 5/3/1993 Farzad Modified for the new SecurityMgr that sets up
- // A5 world for the modules.
- // 12/17/1992 Farzad Created
- //===========================================================================
-
-
-
- #include "SecurityInterface.h"
- #include "SamplePackets.h"
-
- // #define SecurityShellVersion 0x0080
-
-
- //===========================================================================
- // Macros
- //===========================================================================
- #define kMaxRetryCount 2 // number of times to retry password
-
-
- //===========================================================================
- // Types
- //===========================================================================
- typedef enum
- {
- // 0 is used by ARA for the Tickle routine. Although we won't be
- // using the tickle routine to handle any states, we'll start with
- // 1 anyway.
-
- kStateGotOldPassword = 1, // obtained the old password from U&G
- kStateRequestedPassword, // sent a request to the client
- kStateGotResponse, // got response
- kStateSentCancel, // sent a cancel to the other side
- kStateSentAllow, // sent allow user
- kStateMiscCompletion // all other completions we don't care
- // about
- } TServerCodeStates;
-
-
- static struct
- {
- TSamplePacket fout_pkt; // outgoing packet
- TSamplePacket fin_pkt; // incoming packet
-
- char fold_password[ kSecurityMaxConfigData ];
- int ftry_count;
-
- } MyData; // this is the global data for the
- // server side code resource
-
-
-
-
- //===========================================================================
- // Functions
- //===========================================================================
-
- // function prototypes
- static long DoMyStartup( MyReference, LongParam );
- static long DoMyShutdown( MyReference, LongParam );
- static long DoMyBegin( MyReference, LongParam );
- static long DoMyEnd( MyReference, LongParam );
- static long DoMyDataHandler( MyReference, LongParam );
- static long DoMyAbortHandler( MyReference, LongParam );
- static long DoMyTickleHandler( MyReference, LongParam );
- pascal void MyCompletionProc( SecurityReference MyReference,
- int ResultCode,
- void * DataPtr,
- int DataSize,
- long CompletionParam );
- static int are_pwds_same( register char * pwd_1,
- register char * pwd_2 );
- static void pstrcpy( register char * to_str,
- register char * from_str );
-
-
-
-
- // this routine is the entry point for this module. ARA calls this
- // routine.
- pascal long MySecurityProcEntry( SecurityActions Action,
- SecurityReference MyReference,
- long LongParam )
- //===========================================================================
- // Description: this is the entry point for the ??? security operation.
- // It is called by AppleTalk Remote Access to have this
- // security module perform the given operation. It
- // dispatches to a variety of routines based on the
- // requested action.
- //
- // Parameters: Action the action to be performed
- // MyReference this is a unique value representing
- // this instance of this code module.
- // DataPtr the data for this action
- // DataSize the size of data
- //
- // Return Value: long result code, nonzero indicates an
- // error. Its value is one of the
- // SecurityResultCodes.
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- switch ( Action ) {
-
- case kSecurityStartup:
- return DoMyStartup( MyReference, LongParam );
-
-
- case kSecurityShutdown:
- return DoMyShutdown( MyReference, LongParam );
-
-
- case kSecurityBegin:
- return DoMyBegin( MyReference, LongParam );
-
-
- case kSecurityEnd:
- return DoMyEnd( MyReference, LongParam );
-
-
- case kSecurityDataAvailable:
- return DoMyDataHandler( MyReference, LongParam );
-
-
- case kSecurityAbort:
- return DoMyAbortHandler( MyReference, LongParam );
-
-
- case kSecurityTickleAction:
- return DoMyTickleHandler( MyReference, LongParam );
-
- }
-
- return ( kSecurityUnsupportedAction );
- }
-
-
-
-
- static long DoMyStartup( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityStartup action. You
- // should allocate any memory and setup the working
- // environment (e.g. A5 world) here.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // We don't need to do anything for the kSecurityStartup action.
- // Normally we could pre-allocate any needed resources in this
- // routine
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyShutdown( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityShutdown action. You
- // should release any memory allocated by the DoMyStartup
- // routine.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // We don't need to do anything for the kSecurityShutdown action
- // Normally we would release any allocated resources here.
- // This is the very last action sent to a code resource.
- // After returning from this action, the code resource will
- // be unloaded
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyBegin( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityBeing action. This
- // routine should start the operations the code resource
- // must do. For example an authentication code resource
- // should start the authentication process.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(LongParam)
- // get this user's old password
- if ( ARAReadSecurityData( MyReference,
- & MyData.fold_password,
- sizeof( MyData.fold_password ),
- MyCompletionProc,
- kStateGotOldPassword ) != ARANoErr )
- {
- // Some sort of error occured. Stop the operation here.
-
- ARACompleteOperation( MyReference );
- return ( kSecurityGenericErr );
- }
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyEnd( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityEnd action. The action
- // is sent to signal the end of the operation the code
- // resource was created to do.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // The kSecurityEnd action is sent to indicate the end of the operation.
- // We could start the cleanup process here. ARA services are no longer
- // available. We could initiate any external (e.g. outstanding calls to
- // Mac's OS) here. A kSecurityShutdown will be sent later, after which
- // this code resource will be unloaded.
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyDataHandler( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityDataAvailable action.
- // The action is sent when data has arrived for the code
- // resource.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // Currently DataAvailable action is not being used. It may in the future
- // be put to some use. One possible use might be for cases when you have
- // a modeless dialog box. We could send you the events through the use
- // of this action.
-
- // This action might also be used when we get data during
- // the authentication process, and you don't have a read pending.
-
- // Again, it is not used now but may be used in the future!
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyAbortHandler( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityAbort action. The
- // abort action is sent when the code resources operation
- // needs to be terminated abnormally.
- //
- // Parameters: MyReference My unique reference
- // LongParam additional information
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // We are being aborted. You need to abort what you are doing.
- // ARAServices will not be available after this (at least the read and
- // writes will not be available, but you shouldn't expect any of the
- // ARA services to be available). The kSecurityAbort action is sent
- // because of some type of exception.
-
- return ( kSecurityNoErr );
- }
-
-
-
- static long DoMyTickleHandler( MyReference, LongParam )
- //===========================================================================
- // Description: this routine handles the kSecurityTickle action. ARA
- // sends this action periodically. The action is also
- // generated as a result of a call to ARATickleMe routine.
- //
- //
- // Parameters: MyReference My unique reference
- // LongParam When ARA calls this value will be 0,
- // otherwise it is the value passed to
- // the ARATickleMe routine.
- //
- // Return Value: long result code, nonzero indicates error
- //
- // Creation Date:
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(MyReference,LongParam)
-
- // This routine is periodically called by ARA. You can post a tickle
- // action to yourself (e.g. from completion routines) by calling
- // ARATickleMe. This is usually done to perform actions that need
- // to allocate memory or display dialogs, etc.
- // When ARA is sending the kSecurityTickle action the value of
- // LongParam is 0. When the action is sent as a result of a call
- // you made to ARATickleMe, the LongParam will be the value you
- // specify in TickleParam for the ARATickleMe call.
- // You can use the LongParam (TickleParam) as a state indicator.
-
- return ( kSecurityNoErr );
- }
-
-
-
- pascal void MyCompletionProc( SecurityReference MyReference,
- int ResultCode,
- void * DataPtr,
- int DataSize,
- long CompletionParam )
- //===========================================================================
- // Description: this is the completion routine for the ARA calls this
- // module makes. It is called when the asynchronous ARA
- // calls complete.
- // We use the CompletionParam to represent the current
- // state.
- //
- // Parameters: MyReference this code resources unique reference
- // ResultCode the result code for the ARA call
- // DataPtr pointer to the data we passed to the
- // ARA call
- // DataSize actual size of data (e.g. for read
- // calls this is what was read)
- // CompletionParam the current state of our state machine
- //
- // Return Value: none
- //
- // Creation Date: 12/17/1992
- //
- // Modifications:
- //
- //===========================================================================
- {
- #pragma unused(DataPtr,DataSize)
- // This code resource uses one completion routine for all of the
- // asynchronous ARA calls it makes. It uses the CompletionParam as
- // current state value to implement a state machine. The value of
- // CompletionParam is the same as the value passed in the CompletionParam
- // of the corresponding asynchronous ARA routine.
-
- if ( ResultCode == ARAAbort )
- {
- // we are being aborted
- return;
- }
-
- switch ( CompletionParam )
- {
-
- case kStateGotOldPassword: // have got the old password
-
- // prompt the client code resource to get the user to input the
- // additional password. At this point, the client code resource
- // should be loaded and waiting for a prompt from this side.
-
- MyData.fout_pkt.fpkt_type = kPktRequestPassword;
- if ( ARAWrite( MyReference,
- & MyData.fout_pkt,
- sizeof( MyData.fout_pkt ),
- MyCompletionProc,
- kStateRequestedPassword ) != ARANoErr )
- {
- ARACompleteOperation( MyReference );
- return;
- }
-
- // we are going to not allow the user after trying to get the
- // correct password after a few times.
- MyData.ftry_count = 1;
- break;
-
-
- case kStateRequestedPassword:
- // At this point we have requested the password from the client.
- // We need to post a read to get the client's response.
- if ( ARARead( MyReference,
- & MyData.fin_pkt,
- sizeof( MyData.fin_pkt ),
- MyCompletionProc,
- kStateGotResponse ) != ARANoErr )
- {
- ARACompleteOperation( MyReference );
- return;
- }
- break;
-
-
- case kStateGotResponse: // got response
- if ( ResultCode != ARANoErr )
- {
- ARACompleteOperation( MyReference );
- return;
- }
-
- // response is in fin_pkt
- if ( MyData.fin_pkt.fpkt_type == kPktPasswordResponse )
- { int allow_user;
- int next_state;
-
- // The client sent the password the user entered. Compare it
- // to the password we have stored on the server side.
-
- allow_user = are_pwds_same( MyData.fin_pkt.u.fresponse.fpassword,
- MyData.fold_password );
-
- // Regardless of what happens next, we must send the client
- // a response, so we must do a write in all cases. However
- // we will send different result codes, and the next state
- // in our state machine will be one of several.
- // We will use the local variable next_state to determine
- // what the next state will be that we will transition to.
-
- if ( allow_user )
- {
- // the password was ok. Let the client know and
- // transition to the state that allows the user
-
- MyData.fout_pkt.fpkt_type = kPktAllow;
- next_state = kStateSentAllow;
- }
- else
- {
- // Incorrect password. Should we retry?
-
- if ( MyData.ftry_count >= kMaxRetryCount )
- { // passed the retry limit. Don't allow on both
- // sides.
-
- MyData.fout_pkt.fpkt_type = kPktCancel;
- pstrcpy( MyData.fout_pkt.u.freason.fmsg,
- "\puser was not authenticated" );
- next_state = kStateSentCancel;
- }
- else
- { // Request the password from the client again
-
- ++ MyData.ftry_count;
- MyData.fout_pkt.fpkt_type = kPktRequestPassword;
- next_state = kStateRequestedPassword;
- }
- }
- if ( ARAWrite( MyReference,
- & MyData.fout_pkt,
- sizeof( MyData.fout_pkt ),
- MyCompletionProc,
- next_state ) != ARANoErr )
- {
- ARACompleteOperation( MyReference );
- return;
- }
- }
- else
- {
- // the client sent us something other than the password
- // we requested. Just don't allow the user
-
- ARADontAllowUser( MyReference,
- "\pClient canceled authentication",
- MyCompletionProc,
- kStateMiscCompletion );
- }
- break;
-
-
- case kStateSentCancel:
-
- // We have sent the client a cancel. We need to let ARA know
- // the user is not authenticated, and we are finished.
-
- ARADontAllowUser( MyReference,
- "\pUser was not authenticated",
- MyCompletionProc,
- kStateMiscCompletion );
- break;
-
-
- case kStateSentAllow:
-
- // We have already let the client know the user is going to be
- // allowed access to ARA. Now, let ARA know the user was authenticated.
-
- ARAAllowUser( MyReference,
- MyCompletionProc,
- kStateMiscCompletion );
- break;
-
-
- case kStateMiscCompletion:
- default:
- // The kStateMiscCompletion is used for cases that we don't need to
- // do anything for.
- break;
-
-
- }
-
- return;
- }
-
-
- static int are_pwds_same( register char * pwd_1,
- register char * pwd_2 )
- //===========================================================================
- // Description: this routine compares two passwords for equality. The
- // strings are pascal strings.
- //
- // Parameters: pwd_1 one of the two pascal string passwords
- // pwd_2 the other pascal string password (amazing!)
- //
- // Return Value: int nonzero if the two passwords are equal
- // zero otherwise
- //
- // Creation Date: 12/17/1992
- //
- // Modifications:
- //
- //===========================================================================
- { register int ri;
-
- // Basically compares two pascal strings.
- // Note: it is case sensitive
-
- for ( ri = pwd_1[ 0 ] ; ri >= 0; -- ri )
- { // a little faster than doing ri <= pwd_1[ 0 ]
-
- // first time around compares the length bytes
-
- if ( * ( pwd_1 ++ ) != * ( pwd_2 ++ ))
- {
- return ( false );
- }
- }
-
- return ( true ); // they match
- }
-
-
- static void pstrcpy( register char * to_str,
- register char * from_str )
- //===========================================================================
- // Description: copies a pascal string from from_str to to_str.
- //
- // Parameters: to_str where the string is copied to
- // from_str where the string is copied from
- //
- // Return Value: none
- //
- // Creation Date: 12/17/1992
- //
- // Modifications:
- //
- //===========================================================================
- { register int ri;
-
- for ( ri = from_str[ 0 ]; ri >= 0; -- ri )
- {
- * ( to_str ++ ) = * ( from_str ++ );
- }
-
- return;
- }